﻿using System.ComponentModel;

namespace PmSoft.Core.Extensions;

/// <summary>
/// 字典类型的扩展方法集合
/// </summary>
public static class DictionaryExtensions
{
	/// <summary>
	/// 向字典中添加或更新值
	/// </summary>
	/// <typeparam name="TKey">键的类型</typeparam>
	/// <typeparam name="TValue">值的类型</typeparam>
	/// <param name="dictionary">要操作的字典</param>
	/// <param name="key">键</param>
	/// <param name="addValue">要添加的新值</param>
	/// <param name="updateValueFactory">用于更新现有值的委托函数</param>
	/// <returns>添加或更新后的值</returns>
	public static TValue AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
	{
		if (!dictionary.ContainsKey(key))
		{
			dictionary.Add(new KeyValuePair<TKey, TValue>(key, addValue));
		}
		else
		{
			dictionary[key] = updateValueFactory(key, dictionary[key]);
		}

		return dictionary[key];
	}

	/// <summary>
	/// 尝试从字典中获取值，如果键不存在则返回默认值
	/// </summary>
	/// <typeparam name="TKey">键的类型</typeparam>
	/// <typeparam name="TValue">值的类型</typeparam>
	/// <param name="dictionary">要查询的字典</param>
	/// <param name="key">要查找的键</param>
	/// <param name="value">输出参数，存储找到的值</param>
	/// <param name="defaultValue">当键不存在时返回的默认值</param>
	/// <returns>如果找到键则返回对应的值，否则返回默认值</returns>
	public static TValue TryGetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, out TValue value, TValue defaultValue)
		where TValue : notnull
	{
		if (dictionary.TryGetValue(key, out var result))
		{
			value = result;
			return result;
		}
		value = defaultValue;
		return defaultValue;
	}

	/// <summary>
	/// 尝试从字典中获取值并转换为指定类型
	/// </summary>
	/// <typeparam name="T">要转换的目标类型</typeparam>
	/// <param name="dictionary">要查询的字典</param>
	/// <param name="key">要查找的键</param>
	/// <param name="converter">可选的值转换器</param>
	/// <returns>转换后的值，如果转换失败则返回默认值</returns>
	/// <exception cref="InvalidOperationException">当值转换失败时抛出</exception>
	public static T? TryGetValue<T>(this IDictionary<string, object> dictionary, string key, Func<object, T>? converter = null)
	{
		if (!dictionary.TryGetValue(key, out var value))
		{
			return default;
		}

		if (converter != null)
		{
			return converter.Invoke(value);
		}

		try
		{
			return (T)value;
		}
		catch (InvalidCastException)
		{
			try
			{
				if (typeof(T).IsValueType)
				{
					// 对于值类型，使用 TypeConverter 进行转换
					var typeConverter = TypeDescriptor.GetConverter(typeof(T));
					var stringValue = value.ToString() ?? string.Empty;
					return (T?)typeConverter.ConvertFromString(stringValue);
				}

				// 对于引用类型，尝试通过 JSON 反序列化
				var jsonValue = value.ToString() ?? string.Empty;
				return Json.Parse<T>(jsonValue);
			}
			catch (Exception ex)
			{
				throw new InvalidOperationException($"无法将键 {key} 的值转换为类型 {typeof(T).Name}", ex);
			}
		}
	}
}